

/*
 * Copyright (c) 2021. Dylan Cai
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

@file:Suppress("unused")

package com.gitee.wsl.ext.base

import com.gitee.wsl.time.DATA
import com.gitee.wsl.time.DATA_TIME
import com.gitee.wsl.time.TIME
import com.gitee.wsl.time.YEAR_MONTH
import com.gitee.wsl.time.atEndOfDay
import com.gitee.wsl.time.atEndOfWeek
import com.gitee.wsl.time.atStartOfDay
import com.gitee.wsl.time.atStartOfWeek
import com.gitee.wsl.time.epochNanoseconds
import com.gitee.wsl.time.now
import com.gitee.wsl.time.timestamp
import kotlin.time.Clock
import kotlin.time.Instant
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlin.time.ExperimentalTime

/**
 * 定义一个可调式的时间获取接口 用于调试时 currentTimeMillis 计算 delay 跳过问题
 *
 * 在Test类中 使用 useTestClock() 注册先
 *
 * class TestTimestampClock(private val scheduler: TestCoroutineScheduler) : TimestampClock {
 *     @OptIn(ExperimentalCoroutinesApi::class)
 *     @ExperimentalTime
 *     override fun now() = scheduler.currentTime
 * }
 *
 * fun TestScope.useTestClock() {
 *     com.gitee.wsl.ext.base.timestampClock = TestTimestampClock(testScheduler)
 * }
 *
 */
@OptIn(ExperimentalTime::class)
interface TimestampClock{

    val currentTime:Instant get() = Clock.System.now()

    val currentTimeSecond :Long get() = currentTime.epochSeconds

    val currentTimeMilliseconds :Long get() = currentTime.toEpochMilliseconds()

    val currentTimeNanoseconds:Long get() = currentTime.epochNanoseconds

    //val currentTimeNanoseconds:Long get() = TimeSource.Monotonic.markNow().elapsedNow().inWholeNanoseconds

    companion object:TimestampClock
}


var timestampClock:TimestampClock = TimestampClock

var currentTimeZone: TimeZone = TimeZone.currentSystemDefault()

@OptIn(ExperimentalTime::class)
inline val currentTime:Instant get() = timestampClock.currentTime

inline val currentTimeSecond :Long get() = timestampClock.currentTimeSecond

inline val currentTimeMillis:Long get() = timestampClock.currentTimeMilliseconds

inline val currentTimeNanoseconds:Long get() = timestampClock.currentTimeNanoseconds

inline val currentDateTime: LocalDateTime
    get() = LocalDateTime.now()

inline val today: LocalDate
    get() = currentDateTime.date

inline val startOfToday: LocalDateTime
    get() = today.atStartOfDay()

inline val endOfToday : LocalDateTime
    get() = today.atEndOfDay()

inline val startOfWeek: LocalDate
    get() = today.atStartOfWeek

inline val endOfWeek : LocalDate
    get() = today.atEndOfWeek

fun LocalDateTime.toDateTimeString() = LocalDateTime.Formats.DATA_TIME.format(this) // 2020-08-05 13:14:15

fun LocalDateTime.toDateString() = LocalDateTime.Formats.DATA.format(this) // 2020-08-05

fun LocalDateTime.toTimeString() = LocalDateTime.Formats.TIME.format(this) // 13:14:15

fun LocalDateTime.toYearMonthString() = LocalDateTime.Formats.YEAR_MONTH.format(this) // 2020-08

fun LocalDateTime.toTimestampString() = timestamp.toString()

fun LocalDate.toYearMonthString() = LocalDate.Formats.YEAR_MONTH.format(this) // 2020-08

fun LocalDate.toTimestampString() = timestamp.toString()
